#include <bits/stdc++.h>
#include "main.h"
#include "boat.h" 
using namespace std;

Boat boat[boat_num];	// 船舶信息
queue<int> come_q;
queue<int> go_q;

// 找泊位
static int find_maxberth()
{
    double max_exp = -1;
    int ans = -1;
    for (int i = 0; i < worth_berth.size(); i++) {
		int index = worth_berth[i];
		Berth &bt = berth[index];
		double exp = -1;
		// 假如该泊位有船，则计算泊位上的货物是否足够，并且剩余装载时间是否小于航行时间
		if (bt.status == 1 && frame_id + 2 * bt.transport_time < frame_num && bt.goods_num > 0) {
			Boat &b = boat[bt.boat_ids.back()]; // 要去该泊位的或者已经在该泊位的船
			// 假如船已经在泊位上
			if (b.status != 0 && b.pos == index) {
				//int boat_full_time = (boat_capacity - boat.goods_num) / bt.loading_speed; // 泊位上船装满还要多久
				int reserve_goods = bt.goods_num - (boat_capacity - b.goods_num); // 把当前泊位船装满后还剩多少货物
				if (reserve_goods > 0)
					exp = (bt.goods_price / bt.goods_num) * min(reserve_goods, bt.loading_speed * (frame_num - (frame_id + 2 * bt.transport_time)));
			} 
			// 假如船准备去该泊位，但是还没到
			else {
				int arrive_time1 = b.arrive_time;
				int arrive_time2 = frame_id + bt.transport_time;
				// 假如第一个船先到
				if (arrive_time1 < arrive_time2) {
					int boat_full_time = (boat_capacity - b.goods_num) / bt.loading_speed; // 第一个到达的船装满要多久
					int reserve_goods = bt.goods_num - (boat_capacity - b.goods_num); // 把第一个船装满后还剩多少货物
					if (arrive_time2 - arrive_time1 >= boat_full_time && reserve_goods > 0)
						exp = (bt.goods_price / bt.goods_num) * min(reserve_goods, bt.loading_speed * (frame_num - (frame_id + 2 * bt.transport_time)));
				} 
			}
		} 
		// 假如泊位上没有船，则对比期望来选择泊位
		else if (bt.status == 0 && frame_id + 2 * bt.transport_time < frame_num && bt.goods_num > 0){
			exp = (bt.goods_price / bt.goods_num) * min(bt.goods_num, bt.loading_speed * (frame_num - (frame_id + 2 * bt.transport_time)));
		}
		
		if (exp > max_exp) {
			ans = index;
			max_exp = exp;
		}
	}
	return ans;
}

// 换泊位
static int change_berth(int boat_id)
{
    double max_exp = -1;
    int ans = -1;
    for (int i = 0; i < worth_berth.size(); i++) {
		int index = worth_berth[i];
		Berth &bt = berth[index];
		double exp = -1;
		int expire_time = 500 + frame_id + bt.transport_time + frame_deviation + max((boat_capacity - boat[boat_id].goods_num) - 13, 8) / bt.loading_speed;
		// 假如该泊位有船，则计算泊位上的货物是否足够，并且剩余装载时间是否小于500
		if (bt.status == 1 && expire_time < frame_num && bt.goods_num > 0) {
			Boat &b = boat[bt.boat_ids.back()]; // 要去该泊位的或者已经在该泊位的船
			// 假如船已经在泊位上
			if (b.status != 0 && b.pos == index) {
				//int boat_full_time = (boat_capacity - boat[bt.boat_ids.back()].goods_num) / bt.loading_speed; // 泊位上船装满还要多久
				int reserve_goods = bt.goods_num - (boat_capacity - b.goods_num); // 把当前泊位船装满后还剩多少货物
				if (reserve_goods > max((boat_capacity - boat[boat_id].goods_num) - 13, 8))
					exp = 200 * (bt.goods_price / bt.goods_num) / reserve_goods;
			} 
			// 假如船准备去该泊位，但是还没到
			else {
				int arrive_time1 = b.arrive_time;
				int arrive_time2 = frame_id + 500;
				// 假如第一个船先到
				if (arrive_time1 < arrive_time2) {
					int boat_full_time = (boat_capacity - b.goods_num) / bt.loading_speed; // 第一个到达的船装满要多久
					int reserve_goods = bt.goods_num - (boat_capacity - b.goods_num); // 把第一个船装满后还剩多少货物
					if (arrive_time2 - arrive_time1 >= boat_full_time && reserve_goods > max((boat_capacity - boat[boat_id].goods_num) - 13, 8))
						exp = 200 * (bt.goods_price / bt.goods_num) / reserve_goods;
				} 
			}
		} 
		// 假如泊位上没有船，则对比期望来选择泊位
		else if (bt.status == 0 && bt.goods_num >= max((boat_capacity - boat[boat_id].goods_num) - 13, 8) && expire_time < frame_num && bt.goods_num > 0){
			exp = 200 * (bt.goods_price / bt.goods_num) / bt.goods_num;
		}
		
		if (exp > max_exp) {
			ans = index;
			max_exp = exp;
		}
	}
	return ans;
}

// 换泊位
static int change_berth2(int boat_id)
{
    double max_exp = -1;
    int ans = -1;
    for (int i = 0; i < worth_berth.size(); i++) {
		int index = worth_berth[i];
		Berth &bt = berth[index];
		double exp = -1;
		int expire_time = 500 + frame_id + bt.transport_time + frame_deviation + min(boat_capacity - boat[boat_id].goods_num, 3) / bt.loading_speed;
		// 假如该泊位有船，则计算泊位上的货物是否足够，并且剩余装载时间是否小于500
		if (bt.status == 1 && expire_time < frame_num && bt.goods_num > 0) {
			Boat &b = boat[bt.boat_ids.back()]; // 要去该泊位的或者已经在该泊位的船
			// 假如船已经在泊位上
			if (b.status != 0 && b.pos == index) {
				//int boat_full_time = (boat_capacity - boat[bt.boat_ids.back()].goods_num) / bt.loading_speed; // 泊位上船装满还要多久
				int reserve_goods = bt.goods_num + b.goods_num - boat_capacity; // 把当前泊位船装满后还剩多少货物
				if (reserve_goods >= min(boat_capacity - boat[boat_id].goods_num, 3))
					exp = (bt.goods_price / bt.goods_num) * reserve_goods;
			}
			// 假如船准备去该泊位，但是还没到
			else {
				int arrive_time1 = b.arrive_time;
				int arrive_time2 = frame_id + 500;
				// 假如第一个船先到
				if (arrive_time1 < arrive_time2) {
					int boat_full_time = (boat_capacity - b.goods_num) / bt.loading_speed; // 第一个到达的船装满要多久
					int reserve_goods = bt.goods_num - (boat_capacity - b.goods_num); // 把第一个船装满后还剩多少货物
					if (arrive_time2 - arrive_time1 >= boat_full_time && reserve_goods >= min(boat_capacity - boat[boat_id].goods_num, 3))
						exp = (bt.goods_price / bt.goods_num) * reserve_goods;
				} 
			}
		} 
		// 假如泊位上没有船，则对比期望来选择泊位
		else if (bt.status == 0 && bt.goods_num >= min(boat_capacity - boat[boat_id].goods_num, 3) && expire_time < frame_num && bt.goods_num > 0){
			exp = bt.goods_price;
		}
		if (exp > max_exp) {
			ans = index;
			max_exp = exp;
		}
	}
	return ans;
}

// 换泊位
static int change_berth3(int boat_id)
{
    double max_exp = -1;
    int ans = -1;
    for (int i = 0; i < worth_berth.size(); i++) {
		int index = worth_berth[i];
		Berth &bt = berth[index];
		double exp = -1;
		int expire_time = 500 + frame_id + bt.transport_time + frame_deviation + min(boat_capacity - boat[boat_id].goods_num, 11) / bt.loading_speed;
		// 假如该泊位有船，则计算泊位上的货物是否足够，并且剩余装载时间是否小于500
		if (bt.status == 1 && expire_time < frame_num && bt.goods_num > 0) {
			Boat &b = boat[bt.boat_ids.back()]; // 要去该泊位的或者已经在该泊位的船
			// 假如船已经在泊位上
			if (b.status != 0 && b.pos == index) {
				//int boat_full_time = (boat_capacity - boat[bt.boat_ids.back()].goods_num) / bt.loading_speed; // 泊位上船装满还要多久
				int reserve_goods = bt.goods_num + b.goods_num - boat_capacity; // 把当前泊位船装满后还剩多少货物
				if (reserve_goods >= min(boat_capacity - boat[boat_id].goods_num, 11))
					exp = (bt.goods_price / bt.goods_num) * reserve_goods;
			}
			// 假如船准备去该泊位，但是还没到
			else {
				int arrive_time1 = b.arrive_time;
				int arrive_time2 = frame_id + 500;
				// 假如第一个船先到
				if (arrive_time1 < arrive_time2) {
					int boat_full_time = (boat_capacity - b.goods_num) / bt.loading_speed; // 第一个到达的船装满要多久
					int reserve_goods = bt.goods_num - (boat_capacity - b.goods_num); // 把第一个船装满后还剩多少货物
					if (arrive_time2 - arrive_time1 >= boat_full_time && reserve_goods >= min(boat_capacity - boat[boat_id].goods_num, 11))
						exp = (bt.goods_price / bt.goods_num) * reserve_goods;
				} 
			}
		} 
		// 假如泊位上没有船，则对比期望来选择泊位
		else if (bt.status == 0 && bt.goods_num >= min(boat_capacity - boat[boat_id].goods_num, 11) && expire_time < frame_num && bt.goods_num > 0){
			exp = bt.goods_price;
		}
		if (exp > max_exp) {
			ans = index;
			max_exp = exp;
		}
	}
	return ans;
}

// 船执行任务
void boat_task(int boat_id)
{
	int flags = 0;
	if (!come_q.empty() && boat_id == come_q.back() && boat[boat_id].status != 0) {
		flags = 1;
		ship(boat_id, boat[boat_id].target_id);
		come_q.pop();
	}
	if (!go_q.empty() && boat_id == go_q.back() && boat[boat_id].status != 0) {
		flags = 1;
		go(boat_id);
		go_q.pop();
	}
	if(flags)
		return;
		
	//if (frame_id < 1000)
	//	return;
		
    // 如果船在虚拟点，运输完成，则让其返回商品最多并且没有船的泊位
    if (boat[boat_id].status == 1 && boat[boat_id].pos == -1) {
        int berth_id = find_maxberth();
        if (berth_id != -1) {
        	int transport_time = berth[berth_id].transport_time;
        	if (transport_time > min_transport_time + 500) {
        		ship(boat_id, min_time_berthid);
        		boat[boat_id].arrive_time = frame_id + min_transport_time + 500;
        		boat[boat_id].target_id = berth_id;
        		come_q.push(boat_id);
        	} 
        	else {
            	ship(boat_id, berth_id);
            	boat[boat_id].arrive_time = frame_id + berth[berth_id].transport_time;
            }
            ++berth[berth_id].status;
            berth[berth_id].boat_ids.push_front(boat_id);
            
            //fprintf(stderr, "select %d %d %d %d\n", boat_id, berth_id, berth[berth_id].transport_time, frame_id); 
    		//fflush(stdout);
        }
    }
    // 如果船在泊位，并且状态为装货状态，则计算船的装货数量
    else if (boat[boat_id].status == 1 && boat[boat_id].pos != -1) {
        int berth_id = boat[boat_id].pos;
        int berth_goods_num = berth[berth_id].goods_num;
        int max_ship_capacity = boat_capacity - 14;
        // 如果船装货物或者时间快结束了，则让其出发卖掉货物
        if (boat[boat_id].goods_num > boat_capacity - 1 || (boat[boat_id].goods_num != 0 && berth[berth_id].transport_time + frame_id + frame_deviation >= frame_num)) {
        	int transport_time = berth[berth_id].transport_time;
        	if (transport_time > min_transport_time + 500) {
        		ship(boat_id, min_time_berthid);
        		boat[boat_id].arrive_time = frame_id + min_transport_time + 500;
        		go_q.push(boat_id);
        	} 
        	else {
            	go(boat_id);
            	boat[boat_id].arrive_time = frame_id + berth[berth_id].transport_time;
            }
            //fprintf(stderr, "%d %d %d %d\n", boat_id, boat[boat_id].goods_num, berth[berth_id].transport_time, frame_id); 
    		//fflush(stdout);
            boat[boat_id].goods_num = 0;
            --berth[berth_id].status;
            berth[berth_id].boat_ids.pop_back();
            boat[boat_id].change_berth = 0;
            boat[boat_id].wait_time = 0;
        }
        // 如果还没装好，并且泊位还有商品，则继续装货
        else if (berth_goods_num > 0) {
            int upload_goods_num = min(min(berth_goods_num, berth[berth_id].loading_speed), boat_capacity - boat[boat_id].goods_num);
            //berth[berth_id].goods_price -= berth[berth_id].goods_price_list.back();
            //berth[berth_id].goods_price_list.pop_back();
            for (int i = 0; i < upload_goods_num; i++) {
            	berth[berth_id].goods_price -= berth[berth_id].goods_price_list.back();
             	berth[berth_id].goods_price_list.pop_back();
            }
            berth[berth_id].goods_num -= upload_goods_num;
            //if (berth[berth_id].goods_num == 0)
            //	berth[berth_id].goods_index = 0;
            boat[boat_id].goods_num += upload_goods_num;
        }
        // 泊位没商品了，并且船上的货物还不够多，则再扫描去看看其他泊位
        else if ((boat[boat_id].goods_num < max_ship_capacity && boat[boat_id].change_berth < 2) || berth[berth_id].transport_time + 2 * min_transport_time + frame_id + frame_deviation > frame_num){
        	int id;
        	if (frame_id < 1800 && maps != 1)
        		id = change_berth3(boat_id);
        	else if (berth[berth_id].transport_time + 2 * min_transport_time + frame_id + frame_deviation > frame_num)
        		id = change_berth2(boat_id);
        	else 
        	 	id = change_berth(boat_id);
		    if (id != -1) {
		    	//fprintf(stderr, "ship %d %d %d %d\n", boat_id, boat[boat_id].goods_num, berth[berth_id].transport_time, frame_id); 
    			//fflush(stdout);
		        ship(boat_id, id);
		        ++berth[id].status;
		        --berth[berth_id].status;
		        berth[id].boat_ids.push_front(boat_id);
		        boat[boat_id].arrive_time = frame_id + 500;
            	berth[berth_id].boat_ids.pop_back();
            	++boat[boat_id].change_berth;
            	boat[boat_id].wait_time = 0;
		    } 
		    else {
		    	++boat[boat_id].wait_time;
		    }
			if (maps == 1 || maps == 2) {
				if (boat[boat_id].wait_time >= 5 && boat[boat_id].goods_num > 20)
		    		boat[boat_id].change_berth = 2;
			}
			else {
		    	if (boat[boat_id].wait_time >= 10)
		    		boat[boat_id].change_berth = 2;
			}
        } 
        // 泊位没商品了，而且一直没有机器人来送货，直接开去虚拟点
        else if (berth[berth_id].robot_num == 0 && (berth[berth_id].transport_time  + max_transport_time + min_transport_time + frame_id + frame_deviation < frame_num))  {
        	int transport_time = berth[berth_id].transport_time;
        	if (transport_time > min_transport_time + 500) {
        		ship(boat_id, min_time_berthid);
        		boat[boat_id].arrive_time = frame_id + min_transport_time + 500;
        		go_q.push(boat_id);
        	} 
        	else {
        		go(boat_id);
        		boat[boat_id].arrive_time = frame_id + berth[berth_id].transport_time;
        	}
        	//fprintf(stderr, "wait %d %d %d %d\n", boat_id, boat[boat_id].goods_num, berth[berth_id].transport_time, frame_id); 
    		//fflush(stdout);
            boat[boat_id].goods_num = 0;
            --berth[berth_id].status;
            berth[berth_id].boat_ids.pop_back();
            boat[boat_id].change_berth = 0;
            boat[boat_id].wait_time = 0;
        }
    } 
    // 如果船在泊位等待，暂时不执行操作
    //else if (boat[boat_id].status == 2 && boat[boat_id].pos != -1) {
    else if (boat[boat_id].status != 0) {
        //int berth_id = boat[boat_id].pos;
        //fprintf(stderr, "else %d %d %d %d\n", boat_id, boat[boat_id].status, boat[boat_id].pos, frame_id); 
    	//fflush(stdout);
    }
}
